package com.huan.es8.aggregations.bucket;

import co.elastic.clients.elasticsearch._types.mapping.DateProperty;
import co.elastic.clients.elasticsearch._types.mapping.KeywordProperty;
import co.elastic.clients.elasticsearch._types.mapping.Property;
import co.elastic.clients.elasticsearch.core.SearchRequest;
import co.elastic.clients.elasticsearch.core.SearchResponse;
import com.huan.es8.AbstractEs8Api;
import org.junit.jupiter.api.*;

import java.io.IOException;
import java.util.Arrays;

/**
 * <pre>
 * 日期范围聚合
 * 1. 通过日期范围来进行聚合。
 * 2. from 和 to 区间是左闭右开区间 [from, to)
 * 3. 支持的日期格式： <a href="https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html">DateTimeFormatter</a>
 * </pre>
 *
 * @author huan.fu
 * @date 2022/11/23 - 22:22
 * @see <a href="https://www.elastic.co/guide/en/elasticsearch/reference/current/search-aggregations-bucket-daterange-aggregation.html">官方文档</a>
 * @see <a href="https://www.pipiho.com/es/7.7/cn/search-aggregations-bucket-daterange-aggregation.html">官方文档</a>
 * @see <a href="https://blog.csdn.net/fu_huo_1993/article/details/128093563">博客地址</a>
 */
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class DateRangeAggs extends AbstractEs8Api {

    @BeforeAll
    public void createIndex() throws IOException {
        client.indices()
                .create(indexRequest ->
                        indexRequest.index("index_api_invoked_time")
                                .mappings(mappings ->
                                        mappings.properties("id", new Property(new KeywordProperty.Builder().build()))
                                                .properties("api", new Property(new KeywordProperty.Builder().build()))
                                                .properties("invoked_time", new Property(new DateProperty.Builder().format("yyyy-MM-dd HH:mm:ss").build()))
                                )
                );
        bulk("index_api_invoked_time", Arrays.asList(
                "{\"api\":\"/user/infos\",\"invoked_time\": \"2022-11-26 00:00:00\"}",
                "{\"api\":\"/user/add\"}",
                "{\"api\":\"/user/update\",\"invoked_time\": \"2022-11-26 23:59:59\"}",
                "{\"api\":\"/user/list\",\"invoked_time\": \"2022-11-27 00:00:00\"}",
                "{\"api\":\"/user/export\",\"invoked_time\": \"2022-11-29 23:59:59\"}",
                "{\"api\":\"/user/detail\",\"invoked_time\": \"2022-12-01 01:00:00\"}"
        ));
    }

    @Test
    @DisplayName("日期范围聚合")
    public void test01() throws IOException {
        SearchRequest request = SearchRequest.of(searchRequest ->
                searchRequest.index("index_api_invoked_time")
                        .size(0)
                        .aggregations("agg_01", agg ->
                                agg.dateRange(dateRange ->
                                        // 日期字段
                                        dateRange.field("invoked_time")
                                                // 日期格式化
                                                .format("yyyy-MM-dd HH:mm:ss")
                                                // 当文档中缺失 invoked_time 字段时，该给这个默认值
                                                .missing(missing -> missing.stringValue("2022-11-26 00:00:00"))
                                                // 指定时区， 比如下方的 key="2022-11-26 00:00:00"，加上这个时区就是 "2022-11-26 00:00:00 +8" -> 然后转换成0时区，去es中做比较
                                                .timeZone("+8")
                                                // ranges 中的 key 作为json对象的key
                                                .keyed(true)
                                                // 统计 >=2022-11-26 00:00:00 && <2022-11-29 23:59:59的数据
                                                .ranges(ranges ->
                                                        ranges.from(from -> from.expr("2022-11-26 00:00:00"))
                                                                .to(to -> to.expr("2022-11-29 23:59:59"))
                                                                .key(">=2022-11-26 00:00:00 && <2022-11-29 23:59:59的数据")
                                                )
                                                // 统计 >=2022-11-26 00:00:00
                                                .ranges(ranges ->
                                                        ranges.from(from -> from.expr("2022-11-26 00:00:00"))
                                                                .key(">=2022-11-26 00:00:00")
                                                )
                                                // 统计 <2022-11-29 23:59:59的数据
                                                .ranges(ranges ->
                                                        ranges
                                                                .to(to -> to.expr("2022-11-29 23:59:59"))
                                                                .key("<2022-11-29 23:59:59的数据")
                                                )
                                                // 统计15分钟之内的数据之内的数据
                                                .ranges(ranges ->
                                                        ranges.from(from -> from.expr("now-15m"))
                                                                .to(to -> to.expr("now"))
                                                                .key("15分钟之内的数据")
                                                )
                                )
                        )
        );
        System.out.println("request: " + request);
        SearchResponse<String> response = client.search(request, String.class);
        System.out.println("response: " + response);
    }

    @AfterAll
    public void deleteIndex() throws IOException {
        deleteIndex("index_api_invoked_time");
    }
}
